package com.huar.ai;

import com.huar.ai.poi.Dog;
import com.huar.ai.utils.Excel;
import com.huar.ai.utils.POIUtils;
import com.huar.ai.utils.ReflectUtils;
import com.huar.ai.utils.StringUtils;
import org.apache.http.entity.ContentType;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhang
 * @description
 * @date 2021/12/17 09:54
 **/
public class DataValidity {
    public static void main(String[] args) throws IOException, InvalidFormatException, InstantiationException, IllegalAccessException {
        String rootPath = System.getProperty("user.dir");
        String filePath = rootPath + "/src/main/resources/workbook.xlsx";
        File file = new File(filePath);
        FileInputStream fileInputStream = new FileInputStream(file);
        MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(),
                ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream);

        List<List<Map<String, Object>>> mapList = POIUtils.getExcelDataValidations(multipartFile);
        mapList.forEach(list -> {
            list.forEach(map -> {
                map.forEach((k, v) -> {
                    System.out.println(k + ":" + v);
                });
                System.out.println("======================================");
            });
        });
    }

    public static List<Dog> getFile(FileInputStream fileInputStream) throws IOException, InvalidFormatException, InstantiationException, IllegalAccessException {
        Workbook workbook = WorkbookFactory.create(fileInputStream);
        List<Dog> list = new ArrayList<>();
        // 默认读取第一个sheet页
        Sheet sheet = sheet = workbook.getSheetAt(0);
        int rows = sheet.getPhysicalNumberOfRows();

        if (rows > 0) {
            // 定义一个map用于存放excel列的序号和field.
            Map<String, Integer> cellMap = new HashMap<String, Integer>();
            // 获取表头
            Row heard = sheet.getRow(0);
            for (int j = 0; j < heard.getPhysicalNumberOfCells(); j++) {
                Cell cell = heard.getCell(j);
                if (StringUtils.isNotNull(cell)) {
                    String value = getCellValue(heard, j).toString();
                    cellMap.put(value, j);
                } else {
                    cellMap.put(null, j);
                }
            }

            // 有数据时才处理 得到类的所有field.
            Field[] allFields = Dog.class.getDeclaredFields();
            // 定义一个map用于存放列的序号和field.
            Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();
            for (int col = 0; col < allFields.length; col++) {
                Field field = allFields[col];
                Excel attr = field.getAnnotation(Excel.class);
                if (attr != null) {
                    // 设置类的私有字段属性可访问.
                    field.setAccessible(true);
                    Integer column = cellMap.get(attr.name());
                    if (column != null) {
                        fieldsMap.put(column, field);
                    }
                }
            }


            for (int j = 1; j < rows; j++) {
                // 从第2行开始取数据,默认第一行是表头.
                Row row = sheet.getRow(j);
                Dog entity = null;
                for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet()) {
                    Object val = getCellValue(row, entry.getKey());
                    // 如果不存在实例则新建.
                    entity = (entity == null ? Dog.class.newInstance() : entity);
                    // 从map中得到对应列的field.
                    Field field = fieldsMap.get(entry.getKey());

                    // 取得类型,并根据对象类型设置值.
                    Class<?> fieldType = field.getType();
                    if (String.class == fieldType) {
                        String s = val.toString();
                        if (!StringUtils.isEmpty(s)) {
                            s = s.trim();
                        }
                        if (StringUtils.endsWith(s, ".0")) {
                            val = StringUtils.substringBefore(s, ".0");
                        } else {
                            val = s;
                        }
                    }

                    //// TODO: 2021/12/17 目前只支持string，若要做个性化，支持更多类型，请在这里添加相应的代码逻辑

                    if (StringUtils.isNotNull(fieldType)) {
                        String propertyName = field.getName();
                        ReflectUtils.invokeSetter(entity, propertyName, val);
                    }
                }
                list.add(entity);
            }
        }
        return list;
    }

    public static Object getCellValue(Row row, int column) {
        if (row == null) {
            return row;
        }
        Object val = "";
        try {
            Cell cell = row.getCell(column);
            if (StringUtils.isNotNull(cell)) {
                if (cell.getCellTypeEnum() == CellType.NUMERIC || cell.getCellTypeEnum() == CellType.FORMULA) {
                    val = cell.getNumericCellValue();
                    if (HSSFDateUtil.isCellDateFormatted(cell)) {
                        val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
                    } else {
                        if ((Double) val % 1 > 0) {
                            val = new BigDecimal(val.toString());
                        } else {
                            val = new DecimalFormat("0").format(val);
                        }
                    }
                } else if (cell.getCellTypeEnum() == CellType.STRING) {
                    val = cell.getStringCellValue();
                } else if (cell.getCellTypeEnum() == CellType.BOOLEAN) {
                    val = cell.getBooleanCellValue();
                } else if (cell.getCellTypeEnum() == CellType.ERROR) {
                    val = cell.getErrorCellValue();
                }

            }
        } catch (Exception e) {
            return val;
        }
        return val;
    }
}

